﻿#include <learn/topo/half_mesh.h>
#include <learn/topo/topo_builder.h>
#include <learn/topo/topo_explorer.h>

using namespace xi;
using namespace xi::topo;

Half_Mesh::~Half_Mesh()
{
    Topo_Builder builder;
    for (auto v : m_vertices)
        builder.remove_vertex(v);
}

bool Half_Mesh::empty() const
{
    return m_vertices.empty() && m_edges.empty() && m_coedges.empty() && m_faces.empty();
}

std::size_t Half_Mesh::vertex_num() const
{
    return m_vertices.size();
}

std::size_t Half_Mesh::face_num() const
{
    return m_faces.size();
}

std::size_t Half_Mesh::coedge_num() const
{
    return m_coedges.size();
}

std::size_t Half_Mesh::edge_num() const
{
    return m_edges.size();
}

std::unordered_set<VHandle> &Half_Mesh::vertices()
{
    return m_vertices;
}

std::unordered_set<EHandle> &Half_Mesh::edges()
{
    return m_edges;
}

std::unordered_set<CHandle> &Half_Mesh::coedges()
{
    return m_coedges;
}

std::unordered_set<FHandle> &Half_Mesh::faces()
{
    return m_faces;
}

VHandle Half_Mesh::create_vertex()
{
    auto v = Topo_Builder::create_vertex();
    m_vertices.insert(v);
    return v;
}

CHandle Half_Mesh::create_edge(VHandle v1, VHandle v2)
{
    auto e = Topo_Builder::create_edge(v1, v2);
    m_edges.insert(e);

    m_coedges.insert(e->coedge());
    m_coedges.insert(e->coedge()->twin());

    return e->coedge();
}

FHandle Half_Mesh::create_face(const std::vector<CHandle> &es)
{
    auto f = Topo_Builder::create_face(es);
    m_faces.insert(f);
    return f;
}

bool Half_Mesh::remove(VHandle v)
{
    if (v == nullptr)
        return false;

    // 先删除所有与 v 相关的边，注意这里要使用赋值而非引用，因为删除 e 会修改 v->edges()，导致迭代器失效
    auto eList = v->edges();
    for (auto e : eList)
        remove(e);

    // 再删除 v
    m_vertices.erase(v);
    Topo_Builder::remove_vertex(v);

    return true;
}

bool Half_Mesh::remove(EHandle e)
{
    if (e == nullptr)
        return false;

    // 删除相邻的面
    auto co1 = e->coedge();
    auto co2 = e->coedge()->twin();

    // loop 可能没有 face，不过没有关系
    if (co1->wire() != nullptr)
        remove(co1->wire()->face());
    if (co2->wire() != nullptr)
        remove(co2->wire()->face());

    m_coedges.erase(co1);
    m_coedges.erase(co2);
    m_edges.erase(e);

    Topo_Builder::remove_edge(e);
    return true;
}

bool Half_Mesh::remove(FHandle f)
{
    if (f == nullptr)
        return false;

    // 只需要移除所有 face 相关的属性
    m_faces.erase(f);
    Topo_Builder::remove_face(f);

    return true;
}

bool Half_Mesh::remove_isolated_vertex()
{
    Topo_Builder builder;
    for (auto it = m_vertices.begin(); it != m_vertices.end();)
    {
        if ((*it)->edges().empty())
        {
            builder.remove_vertex(*it);
            it = m_vertices.erase(it);
        }
        else
            ++it;
    }
    return false;
}

bool Half_Mesh::remove_isolated_edge()
{
    Topo_Builder builder;
    Topo_Explorer explorer;
    for (auto it = m_edges.begin(); it != m_edges.end();)
    {
        if (explorer.adjacent_edges(*it).empty())
        {
            builder.remove_edge(*it);
            it = m_edges.erase(it);
        }
        else
            ++it;
    }
    return false;
}

bool Half_Mesh::remove_isolated_face()
{
    Topo_Builder builder;
    Topo_Explorer explorer;
    for (auto it = m_faces.begin(); it != m_faces.end();)
    {
        if (explorer.adjacent_faces(*it).empty())
        {
            builder.remove_face(*it);
            it = m_faces.erase(it);
        }
        else
            ++it;
    }
    return false;
}

VHandle Half_Triangle_Mesh::opposite_vertex(CHandle co) const
{
    if (co == nullptr)
        return nullptr;

    VHandle v = nullptr;
    if (co->next() != nullptr)
        v = Topo_Explorer::end_vertex(co->next());
    return v;
}

CHandle Half_Triangle_Mesh::opposite_coedge(FHandle f, VHandle v) const
{
    if (f == nullptr || v == nullptr)
        return nullptr;

    // 取第一个 loop 上的所有顶点
    auto loop = f->wire();
    CHandle co = loop->coedge();

    Topo_Explorer explorer;
    if (explorer.start_vertex(co) == v)
        return co->next();

    while (co->next() != loop->coedge())
    {
        if (explorer.end_vertex(co) == v)
            return co->prev();
        co = co->next();
    }
    return co;
}

bool Half_Triangle_Mesh::flip_edge(EHandle e)
{
    if (e == nullptr)
        return false;

    // 如果是边界就不翻转
    if (e->coedge()->is_boundary() || e->coedge()->twin()->is_boundary())
        return false;

    // 否则执行翻转
    auto co1 = e->coedge();
    auto co2 = co1->twin();

    // 获得相对的顶点
    Topo_Explorer explorer;
    auto v0 = explorer.start_vertex(co1);
    auto v1 = explorer.end_vertex(co1);
    auto v2 = opposite_vertex(co1);
    auto v3 = opposite_vertex(co2);

    // 保存构造新面需要的 coedge
    std::vector<CHandle> f1({co2->prev(), co1->next()});
    std::vector<CHandle> f2({co1->prev(), co2->next()});

    // 移除边
    remove(e);

    if (v2->edges().empty())
        return true;
    if (v3->edges().empty())
        return true;

    // 构造新的边和面
    auto co = create_edge(v2, v3);
    f1.push_back(co);
    f2.push_back(co->twin());
    create_face(f1);
    create_face(f2);

    return true;
}